import {
    Element
} from './element';
import {
    Utils
} from './utils';

export class PathNode extends Element {

    constructor(sf, from, to, attr) {
        if (!attr) {
            attr = {
                name: `${from.name}-${to.name}`,
                reverse: '0',
                lineType: 'solid'
            }
        }
        super(attr.id);
        this.sf = sf;
        this.type = 'path';
        this.from = from;
        this.to = to;
        this.dots = [];
        this.target = null;
        this.name = attr.name;
        this.reverse = attr.reverse;
        this.lineType = attr.lineType;
        this.init();
    }

    init() {
        let fromPoint = this.getFromPoint();
        let toPoint = this.getToPoint();
        let middlePoint = this.getMiddlePoint(fromPoint, toPoint);

        const path = sf.pager.path(`M${fromPoint.x} ${fromPoint.y}L${toPoint.x} ${toPoint.y}`).attr('stroke', sf.options.path.stroke);
        const text = sf.pager.text(middlePoint.x, middlePoint.y - 20, this.name);
        text.attr({
            'font-family': 'Microsoft YaHei',
            'font-size': '12px',
            'fill': '#888888',
            'opacity': '0.7'
        });
        text.mouseover(e => {
            text.attr({
                'cursor': 'pointer',
                'opacity': 1
            });
        });
        text.mouseout(e => {
            text.attr({
                'opacity': 0.7
            });
        });
        text.click(e => {
            sf.options.editable && sf.options.path.onSetting(this);
        });
        const arrow = this.arrow(fromPoint, toPoint, 3);

        this.target = sf.pager.set();
        this.target.push(path);
        this.target.push(text);
        this.target.push(arrow);

        this.sf.addEvent('rectresize', (rect) => {

            let fromPoint = this.getFromPoint();
            let toPoint = this.getToPoint();

            this.target[0].attr('path', `M${fromPoint.x} ${fromPoint.y}L${toPoint.x} ${toPoint.y}`);
            const arrPos = this.getArrowStr(fromPoint, toPoint, 3);
            const arr = 'M' + arrPos[0].x + ' ' + arrPos[0].y + 'L' + arrPos[1].x + ' ' + arrPos[1].y + 'L' + arrPos[2].x + ' ' + arrPos[2].y + 'z';
            this.target[2].attr('path', arr);

            let middlePoint = this.getMiddlePoint(fromPoint, toPoint);
            this.target[1].attr({
                x: middlePoint.x,
                y: middlePoint.y - 20
            });

            if (this.target[3]) {
                const arrPosR = this.getArrowStr(toPoint, fromPoint, 3);
                const arrR = 'M' + arrPosR[0].x + ' ' + arrPosR[0].y + 'L' + arrPosR[1].x + ' ' + arrPosR[1].y + 'L' + arrPosR[2].x + ' ' + arrPosR[2].y + 'z';
                this.target[3].attr('path', arrR);
            }
        });

        this.sf.addEvent('rectremove', (rect) => {
            if (rect.id === this.from.id || rect.id === this.to.id) {
                this.remove();
            }
        });

        this.setPath({reverse: this.reverse, lineType: this.lineType});
    }

    getFromPoint() {
        const rectF = {
            x: this.from.target[0].attr('x'),
            y: this.from.target[0].attr('y'),
            width: this.from.target[0].attr('width'),
            height: this.from.target[0].attr('height')
        };
        const toPoint = {
            x: this.to.target[2].attr('x'),
            y: this.to.target[2].attr('y'),
        };
        return Utils.connPoint(rectF, toPoint);
    }

    getToPoint() {
        const rectT = {
            x: this.to.target[0].attr('x'),
            y: this.to.target[0].attr('y'),
            width: this.to.target[0].attr('width'),
            height: this.to.target[0].attr('height')
        };
        const fromPoint = {
            x: this.from.target[2].attr('x'),
            y: this.from.target[2].attr('y'),
        };
        return Utils.connPoint(rectT, fromPoint);
    }

    getMiddlePoint(fromPoint, toPoint) {
        return {
            x: fromPoint.x >= toPoint.x ? toPoint.x + (fromPoint.x - toPoint.x) / 2 : fromPoint.x + (toPoint.x - fromPoint.x) / 2,
            y: fromPoint.y >= toPoint.y ? toPoint.y + (fromPoint.y - toPoint.y) / 2 : fromPoint.y + (toPoint.y - fromPoint.y) / 2
        };
    }

    // 画箭头，p1 开始位置,p2 结束位置, r箭头的边长
    arrow(p1, p2, r) {
        let arrPos = this.getArrowStr(p1, p2, r);
        let arr = 'M' + arrPos[0].x + ' ' + arrPos[0].y + 'L' + arrPos[1].x + ' ' + arrPos[1].y + 'L' + arrPos[2].x + ' ' + arrPos[2].y + 'z';
        return this.sf.pager.path(arr).attr('stroke-width', 3).attr('stroke', sf.options.path.stroke);
    }

    getArrowStr(p1, p2, r) {
        let atan = Math.atan2(p1.y - p2.y, p2.x - p1.x) * (180 / Math.PI);

        let centerX = p2.x - r * Math.cos(atan * (Math.PI / 180));
        let centerY = p2.y + r * Math.sin(atan * (Math.PI / 180));

        let x2 = centerX + r * Math.cos((atan + 120) * (Math.PI / 180));
        let y2 = centerY - r * Math.sin((atan + 120) * (Math.PI / 180));

        let x3 = centerX + r * Math.cos((atan + 240) * (Math.PI / 180));
        let y3 = centerY - r * Math.sin((atan + 240) * (Math.PI / 180));
        return [p2, {
            x: x2,
            y: y2
        }, {
            x: x3,
            y: y3
        }];
    }

    getPath() {
        return {
            id: this.id,
            name: this.name,
            type: this.type,
            attr: this.attr,
            from: this.from.id,
            to: this.to.id,
            reverse: this.reverse,
            lineType: this.lineType
        };
    }

    setPath(options) {
        if (options) {
            if (options.name) {
                this.target[1].attr('text', this.name = options.name);
            }
            if (options.lineType) {
                this.lineType = options.lineType;
                this.target[0].attr('stroke-dasharray', this.lineType === 'solid' ? '' : '--');
            }
            if (options.reverse) {
                this.reverse = options.reverse;
                if (this.reverse === '1') {
                    if (!this.target[3]) {
                        this.target.push(this.arrow(this.getToPoint(), this.getFromPoint(), 3));
                    }
                } else {
                    if (this.target[3]) {
                        this.target[3].remove();
                        this.target.splice(3, 1);
                    }
                }
            }
            this.attr = options.attr;
        }
    }

    remove() {
        this.target.remove();
        this.sf.removePath(this.id);
    }

}